<template>
	<div class="video-wrap" :style="{ width: `${width}`, height: `${height}` }">
		<view @click="handleControls">
			<video
				:id="videoId"
				:style="{ width: `${width}`, height: `${height}` }"
				:show-casting-button="true"
				:controls="false"
				:src="src"
				:initial-time="initialTime"
				:show-fullscreen-btn="true"
				:direction="90"
				x5-video-player-type="h5"
				:show-center-play-btn="true"
				:autoplay="autoplay"
				:muted="isMute"
				:poster="poster"
				:object-fit="objectFit"
				@play="videoPlay"
				@pause="videoPause"
				@ended="videoEnded"
				@timeupdate="videoTimeUp"
				@loadedmetadata="videoLoaded"
				@waiting="videoWaiting"
				@error="videoError"
				@controlstoggle="onFullScreen"
				@fullscreenclick="backVideoFull"
				@fullscreenchange="onFullScreen"
			></video>
			<!-- @seeked="videoSeeked" -->
		</view>
		<!-- 控制条 -->
		<view v-if="showControls || isFullScreen" :class="['controls-bar', controls ? 'show' : 'hide']" style="z-index: 9999">
			<!-- 播放 -->
			<view class="play-box" @click.stop="videoPlayClick">
				<image src="/static/public/video/pause.png" mode="" class="play-icon" v-if="isVideoPlay"></image>
				<image src="/static/public/video/play.png" mode="" class="play-icon" v-else></image>
			</view>
			<!-- 声音 -->
			<view class="mute-box" @click="videoMuteClick">
				<image src="/static/public/video/sound.png" mode="" class="mute-icon" v-if="!isMute"></image>
				<image src="/static/public/video/mute.png" mode="" class="mute-icon" v-else></image>
			</view>
			<!-- 进度 -->
			<view class="progress">
				<view class="currtime">{{ currentTimeStr }}</view>
				<view class="slider-container">
					<slider
						@change="sliderChange"
						@changing="sliderChanging"
						:step="step"
						:value="sliderValue"
						backgroundColor="#9f9587"
						activeColor="#d6d2cc"
						block-color="#FFFFFF"
						block-size="12"
					/>
				</view>
				<view class="druationTime">{{ druationTimeStr }}</view>
			</view>
			<!-- 倍速 -->
			<view class="play-rate" @click="videoPlayRate" v-if="showRate">{{ playbackRate }}x</view>
			<!-- 全屏 -->
			<!-- <view class="play-full" @click.stop="videoFull">
				<image src="/static/public/video/fullscreen.png" mode="" class="play-icon" @click.stop="videoFull">
				</image>
			</view> -->
			<!-- 倍速菜单 -->
			<ul class="play-rate-menu" :style="{ height: `${height}` }" v-if="showRateMenu">
				<li v-for="item in playbackRates" :key="item" :class="[{ activeRate: playbackRate === item }, 'play-rate-item']" @click="changePlayRate(item)">{{ item }}x</li>
			</ul>
		</view>
	</div>
</template>
<script>
export default {
	name: 'VideoPlayer',
	props: {
		// 视频地址
		videoId: {
			type: String,
			default: 'myVideo'
		},
		// 视频地址
		src: {
			type: String
		},
		// 自动播放
		autoplay: {
			type: Boolean,
			default: true
		},
		// 封面
		poster: {
			type: String
		},
		// 步长，表示占比，取值必须大于0且为整数
		step: {
			type: Number,
			default: 1
		},
		// 初始播放进度，表示占比
		progress: {
			type: Number
		},
		// 视频宽度
		width: {
			type: String,
			default: '100%'
		},
		// 视频高度
		height: {
			type: String,
			default: '390px'
		},
		// 播放错误提示
		errorTip: {
			type: String,
			default: '播放错误'
		},
		// 是否展示倍速
		showRate: {
			type: Boolean,
			default: false
		},
		// 播放速率
		playbackRates: {
			type: Array,
			default: () => [0.8, 1, 1.25, 1.5, 2]
		},
		// 是否播放，控制自动暂停或播放的
		isPlay: {
			type: Boolean,
			default: true
		},
		// 是否显示控制条
		showControls: {
			type: Boolean,
			default: true
		},
		objectFit: {
			type: String,
			default: 'contain' //contain 包含 fill 填充 cover 覆盖
		}
	},
	data() {
		return {
			minHeight: '100%',
			controls: false, //显示播放控件
			isVideoPlay: false, // 是否正在播放
			isMute: true, // 是否静音
			isVideoEnd: false, // 是否播放结束
			showPoster: true, // 是否显示视屏封面
			showLoading: false, // 加载中
			durationTime: 0, //总播放时间 时间戳
			currentTime: 0, //当前播放时间 时间戳
			druationTimeStr: '00:00', //总播放时间 字符串 计算后
			currentTimeStr: '00:00', //当前播放时间 字符串 计算后
			sliderValue: 0, //进度条的值 百分比
			isSeeked: true, //防止进度条拖拽失效
			playbackRate: 1, // 初始播放速率
			showRateMenu: false, //显示播放速率
			initialTime: 0, //初始播放时间
			showContros: false, //是否横屏-小程序
			isFullScreen: false, //是否全屏
			timer: null, //
			timerFullScreenVal: false, //
			timerFullScreen: null, //
			isShow: false, // 控制 Teleport 组件挂载时机
			isTeleport: true // 控制什么时候被传送
		};
	},
	mounted() {
		this.videoPlayer = uni.createVideoContext(this.videoId, this);
		// #ifdef H5
		this.minHeight = window.screen.availHeight;
		// 处理微信不能自动播放
		if (this.autoplay) {
			document.addEventListener(
				'WeixinJSBridgeReady',
				() => {
					if (!this.isVideoPlay) {
						this.videoPlayer.play();
						this.isVideoPlay = true;
					}
				},
				false
			);
			this.$nextTick(() => {
				if (!this.isVideoPlay) {
					this.videoPlayer.play();
					this.isVideoPlay = true;
				}
			});
		}
		// #endif
	},
	watch: {
		isPlay(val, oldVal) {
			if (val == true && !this.isVideoPlay) {
				if (this.videoPlayer) {
					this.videoPlayer.play();
					this.$emit('play');
				}
			} else {
				if (this.videoPlayer) this.videoPlayer.pause();
			}
		}
	},
	onHide() {
		clearTimeout(this.timer);
		clearInterval(this.timerFullScreen);
	},
	methods: {
		toSourceDom(dom) {
			//Teleport 必须
			document.getElementById('sourceBox').appendChild(dom);
		},
		// 自动隐藏控制条
		hideControls() {
			if (!this.isFullScreen) {
				this.timer = setTimeout(() => {
					this.controls = false;
				}, 1000);
			} else {
				this.controls = true;
			}
		},
		// 点击显示/隐藏控制条
		handleControls(e) {
			this.controls = !this.controls;
		},
		// 根据秒获取时间
		formatSeconds(second) {
			second = Math.round(second);
			var hh = parseInt(second / 3600);
			var mm = parseInt((second - hh * 3600) / 60);
			if (mm < 10) mm = '0' + mm;
			var ss = parseInt((second - hh * 3600) % 60);
			if (ss < 10) ss = '0' + ss;
			if (hh < 10) hh = hh == 0 ? '' : `0${hh}:`;
			var length = hh + mm + ':' + ss;
			if (second > 0) {
				return length;
			} else {
				return '00:00';
			}
		},
		// 缓冲
		videoWaiting(e) {
			// 没有缓冲结束事件，所以在不播放的情况触发loading
			if (!this.isVideoPlay) this.showLoading = true;
		},
		// 视频信息加载完成
		videoLoaded(e) {
			this.durationTime = e.detail.duration;
			this.druationTimeStr = this.formatSeconds(this.durationTime);
			this.initialTime = (this.progress / 100) * this.durationTime;
			this.sliderValue = this.progress / 100;
			this.videoPlayer.seek(this.initialTime);
			this.currentTimeStr = this.formatSeconds(this.initialTime);
			this.controls = true;
			this.showLoading = false;
			this.$emit('loadeddata', e.detail.duration);
		},
		// 播放进度更新,触发频率 250ms 一次
		videoTimeUp(e) {
			let sliderValue = Math.round((e.detail.currentTime / this.durationTime) * 100);
			if (this.isSeeked) {
				//判断拖拽完成后才触发更新，避免拖拽失效
				if (sliderValue % this.step === 0)
					// 比例值能被步进值整除
					this.sliderValue = sliderValue;
			}
			this.currentTimeStr = this.formatSeconds(e.detail.currentTime);
			this.$emit('timeupdate', e.detail.currentTime);
		},
		//正在拖动slider
		sliderChanging(e) {
			this.isSeeked = false; // 拖拽过程中，不允许更新进度条
			this.showLoading = true;
			this.videoPlayer.pause();
			this.$emit('seeking');
		},
		// 拖动slider完成后
		sliderChange(e) {
			this.sliderValue = e.detail.value;
			let currentTime = (this.sliderValue / 100) * this.durationTime;
			this.showLoading = false;
			this.isSeeked = true; // 完成拖动后允许更新滚动条
			this.videoPlayer.seek(currentTime);
			if (this.sliderValue < 100) {
				this.videoPlayer.play();
			} else {
				this.videoPlayer.pause();
				this.videoEnded();
			}
			this.hideControls();
			this.$emit('seeked', this.sliderValue);
		},

		// 点击中心播放
		videoPlayCenter() {
			this.videoPlayer.play();
			this.$emit('play');
		},
		// 点击左下角播放/暂停,会触发原始播放/暂停事件,分开写，防止重复触发
		videoPlayClick() {
			if (this.isVideoPlay) {
				this.videoPlayer.pause();
			} else {
				this.videoPlayer.play();
				this.$emit('play');
			}
		},
		// 原始播放
		videoPlay() {
			if (this.pauseTimer) {
				clearTimeout(this.pauseTimer);
			}
			this.isVideoPlay = true;
			this.isVideoEnd = false;
			this.showLoading = false;
			this.hideControls();
		},
		// 原始暂停
		videoPause() {
			// 处理播放结束和拖动会先触发暂停的问题
			this.pauseTimer = setTimeout(() => {
				if (this.isVideoEnd) return;
				if (!this.isSeeked) return;
				this.isVideoPlay = false;
				this.$emit('pause');
			}, 100);
		},
		// 静音
		videoMuteClick() {
			this.isMute = !this.isMute;
		},
		// 播放结束
		videoEnded() {
			// 重置状态
			this.isVideoPlay = false;
			this.showPoster = true;
			this.isVideoEnd = true;
			this.$emit('ended');
			this.backVideoFull();
		},
		// 播放错误
		videoError(e) {
			uni.showToast({
				title: this.errorTip,
				icon: 'none'
			});
			this.$emit('error');
		},
		// 显示倍速
		videoPlayRate() {
			this.showRateMenu = true;
		},
		// 点击倍速
		changePlayRate(rate) {
			this.playbackRate = rate;
			this.videoPlayer.playbackRate(rate);
			this.showRateMenu = false;
			this.hideControls();
		},
		// 点击全屏
		videoFull() {
			this.videoPlayer.requestFullScreen();
			this.isFullScreen = true;
			if (this.timerFullScreen) clearInterval(this.timerFullScreen);
			this.timerFullScreen = setInterval(() => {
				if (this.isFullScreen) this.timerFullScreenVal = !this.timerFullScreenVal;
			}, 1000);
		},
		backVideoFull() {
			this.isFullScreen = false;
			// this.showContros = false;
			try {
				if (this.videoPlayer) this.videoPlayer.exitFullscreen();
			} catch (e) {
				console.log(e);
			}
		},
		// 监听原生全屏事件
		onFullScreen({ detail }) {
			if (detail.fullScreen) {
				this.showContros = true;
			} else {
				this.showContros = false;
			}
		}
	}
};
</script>
<style lang="scss" scoped>
.show {
	opacity: 1 !important;
}

.hide {
	opacity: 0 !important;
	pointer-events: none;
}

.abs-center {
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
}

.video-wrap {
	position: relative;

	.play-btn {
		width: 120rpx;
		height: 120rpx;
	}

	@keyframes run {
		from {
			transform: rotate(0deg);
		}

		to {
			transform: rotate(360deg);
		}
	}

	.loading-btn {
		width: 120rpx;
		height: 120rpx;
		animation: run 0.8s linear 0s infinite;
	}

	.controls-bar {
		width: 100%;
		padding: 1% 1% 1% 0;
		position: absolute;
		bottom: 0;
		left: 0;
		right: 0;
		z-index: 99;
		display: flex;
		align-items: center;
		color: #fff;
		opacity: 1;
		transition: opacity 1s;
		height: 84rpx;

		.play-box,
		.mute-box,
		.play-full {
			width: 84rpx;
			height: 100%;
			display: flex;
			align-items: center;
			justify-content: center;
		}

		.mute-icon {
			width: 40rpx;
			height: 40rpx;
		}

		.play-icon {
			width: 34rpx;
			height: 34rpx;
		}

		.progress {
			display: flex;
			align-items: center;
			flex: 1;
			font-size: 24rpx;
			margin-left: 16rpx;

			.slider-container {
				flex: 1;
				max-width: 58%;
			}

			.currtime {
				color: #ffffff;
				width: 11%;
				height: 100%;
				text-align: center;
				margin-right: 20rpx;
			}

			.druationTime {
				color: #ffffff;
				width: 12%;
				height: 100%;
				text-align: center;
			}
		}

		.play-rate {
			font-size: 32rpx;
			margin-right: 24rpx;
		}

		.play-rate-menu {
			list-style-type: none;
			background-color: rgba(0, 0, 0, 0.7);
			width: 24%;
			padding-top: 26rpx;
			position: absolute;
			right: 0;
			bottom: 0;
			padding-left: 0;
			box-sizing: border-box;
		}

		.play-rate-item {
			line-height: 70rpx;
			font-size: 28rpx;
			text-align: center;
		}

		.play-rate-item:first-child {
			margin-top: 30rpx;
		}

		.activeRate {
			color: #5785e3;
		}
	}
}

@mixin full-screen() {
	// 视频全屏 按钮文字样式在视频内部
	// 全屏后 屏幕宽高不用颠倒
	$width: 100vw;
	$height: 100vh;
	$w: calc(#{$height} * 16 / 9); // 全屏下 视频宽度
	$side: calc((#{$width} - #{$w}) / 2); // 视频两侧空余宽度
}

.cover-view {
	position: absolute;
	// top: var(--safe-area-inset-top);
	top: 50%;
	right: 0;
	transform: translateY(-50%);

	.wrap {
		padding: 20rpx;
		display: flex;
		flex-direction: column;
		align-items: center;

		&.full-screen {
			@include full-screen();
		}
	}

	.text {
		padding: 5rpx 15rpx;
		line-height: 1.4;
		border: 1rpx solid #ffffff;
		border-radius: 10rpx;
	}

	.text + .text {
		margin-top: 20rpx;
	}
}

.video-player--is-cssfullscreen {
	position: fixed;
	left: 0;
	top: 0;
	width: 100%;
	height: 100%;
	background-color: #fff;
	text-align: center;
	z-index: 99999;
}
</style>
